package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.pair.KeyValuePairDto;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.IdentifierUtil;
import qc.module.platform.dto.dict.DictCategoryDto;
import qc.module.platform.dto.dict.DictCategoryQueryConditionDto;
import qc.module.platform.dto.dict.DictItemDto;
import qc.module.platform.dto.dict.DictItemQueryConditionDto;
import qc.module.platform.entity.QcDictCategory;
import qc.module.platform.entity.QcDictItem;
import qc.module.platform.mapper.DictCategoryMapper;
import qc.module.platform.mapper.DictItemMapper;
import qc.module.platform.repository.QcDictCategoryRepository;
import qc.module.platform.repository.QcDictItemRepository;

import java.util.List;
import java.util.Objects;

/**
 * QcDictCategoryService
 *
 * @author QuCheng Tech
 * @since 2024/3/9
 */
@Service
public class DictService {
    private QcDictCategoryRepository categoryRepository;

    @Autowired
    public void setCategoryRepository(QcDictCategoryRepository categoryRepository) {
        this.categoryRepository = categoryRepository;
    }

    private QcDictItemRepository itemRepository;

    @Autowired
    public void setItemRepository(QcDictItemRepository itemRepository) {
        this.itemRepository = itemRepository;
    }

    /**
     * 查询字典分类
     *
     * @param conditionDto 查询条件对象
     * @return List<DictCategoryDto> 字典分类集合
     * @author Qucheng Tech
     * @since 2024/4/17
     */
    public List<DictCategoryDto> queryCategory(DictCategoryQueryConditionDto conditionDto){
        LambdaQueryWrapper<QcDictCategory> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(conditionDto.getKeywords())){
            //模糊匹配字典编码和字典名称
            wrapper.and(p -> {
                p.like(QcDictCategory::getDictcode,conditionDto.getKeywords()).or()
                        .like(QcDictCategory::getName,conditionDto.getKeywords());
            });
        }
        
        List<QcDictCategory> ens = categoryRepository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens)) return DictCategoryMapper.MAPPER.toDtoList(ens);
        return null;
    }

    /**
     * 获取指定字典分类
     *
     * @param dictCode 字典分类编码
     * @return DictCategoryDto
     * @author Qucheng Tech
     * @since 2024/4/17
     */
    public DictCategoryDto getCategory(String dictCode) throws QCPromptException {
        if (StringUtils.isBlank(dictCode)) throw new QCPromptException("字典分类编码不能为空");
        
        QcDictCategory en = categoryRepository.selectById(dictCode);
        if (Objects.nonNull(en)) return DictCategoryMapper.MAPPER.toDto(en);
        return null;
    }

    /**
     * 新增字典分类
     *
     * @param dto
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/17
     */
    public String addCategory(DictCategoryDto dto){
        //1.条件判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getCode())) return QCUnifyReturnValue.Warn("字典分类编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("字典分类名称不能为空");
        
        //2.判断新增对象是否存在，存在则提示
        if (dictCategoryIsExist(dto.getCode())) return QCUnifyReturnValue.Warn("新增对象已经存在");
        
        //3.dto -> entity
        QcDictCategory en = DictCategoryMapper.MAPPER.toEntity(dto);
        
        //3.保存数据
        if (categoryRepository.insert(en) < 0x1) return QCUnifyReturnValue.Warn("新增数据失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改字典分类
     *
     * @param dto
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public String updateCategory(DictCategoryDto dto){
        //1.条件判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("修改对象不能为空");
        if (StringUtils.isBlank(dto.getCode())) return QCUnifyReturnValue.Warn("字典分类编码不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("字典分类名称不能为空");
        
        //2.判断修改对象是否存在
        if (!dictCategoryIsExist(dto.getCode())) return QCUnifyReturnValue.Warn("修改对象不存在");
        
        //3.dto -> entity
        QcDictCategory en = DictCategoryMapper.MAPPER.toEntity(dto);
        
        //4.修改数据
        categoryRepository.updateById(en);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除字典分类
     *
     * @param code 字典分类编码
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public String deleteCategory(String code){
        if (StringUtils.isBlank(code)) return QCUnifyReturnValue.Warn("字典分类编码不能为空");
        
        //查询分类下是否有字典项，有则不允许删除
        LambdaQueryWrapper<QcDictItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcDictItem::getDictcode,code);
        if (CollectionUtils.isNotEmpty(itemRepository.selectList(wrapper))) 
            return QCUnifyReturnValue.Warn("该分类下有字典项，请先删除字典项");
       
        categoryRepository.deleteById(code);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 查询字典项
     * 查询指定字典分类编码字典项集合
     *
     * @param conditionDto
     * @return List<DictItemDto>
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public List<DictItemDto> queryItem(DictItemQueryConditionDto conditionDto) throws QCPromptException {
        //1.条件判空
        if (Objects.isNull(conditionDto)) throw new QCPromptException("查询条件不能为空");
        if (StringUtils.isBlank(conditionDto.getCtgcode())) throw new QCPromptException("分类编码不能为空");
        
        //2.判断分类编码是否存在，不存在则提示
        if (!dictCategoryIsExist(conditionDto.getCtgcode())) throw new QCPromptException("分类编码不存在或已删除");
        
        //3。构建查询条件
        LambdaQueryWrapper<QcDictItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcDictItem::getDictcode,conditionDto.getCtgcode());
        
        if (StringUtils.isNotBlank(conditionDto.getKeywords())){
            wrapper.and(p ->{
               p.like(QcDictItem::getItemid,conditionDto.getKeywords()).or()
                       .like(QcDictItem::getDictcode,conditionDto.getKeywords()).or()
                       .like(QcDictItem::getK,conditionDto.getKeywords()).or()
                       .like(QcDictItem::getV,conditionDto.getKeywords());
            });
        }
        
        if (StringUtils.isNotBlank(conditionDto.getFlag())){
            wrapper.eq(QcDictItem::getFlag,Integer.parseInt(conditionDto.getFlag()));
        }
        
        wrapper.orderByAsc(QcDictItem::getOdr);
        
        //4.查询数据
        List<QcDictItem> ens = itemRepository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens)) return DictItemMapper.MAPPER.toDtoList(ens);
        return null;
    }

    /**
     * 获取指定字典项
     *
     * @param itemId 字典项编码
     * @return DictItemDto
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public DictItemDto getItem(String itemId) throws QCPromptException {
        if (StringUtils.isBlank(itemId)) throw new QCPromptException("字典项编码不能为空");

        QcDictItem en = itemRepository.selectById(itemId);
        if (Objects.nonNull(en)) return DictItemMapper.MAPPER.toDto(en);
        return null;
    }

    /**
     * 新增字典项
     *
     * @param dto
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public String addItem(DictItemDto dto){
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("新增字典项对象不能为空");
        if (StringUtils.isBlank(dto.getCategorycode())) return QCUnifyReturnValue.Warn("字典分类编码不能为空");
        if (StringUtils.isBlank(dto.getK())) return QCUnifyReturnValue.Warn("字典值不能为空");
        if (StringUtils.isBlank(dto.getV())) return QCUnifyReturnValue.Warn("显示文本不能为空");

        //判断分类编码是否存在，不存在则提示
        if (!dictCategoryIsExist(dto.getCategorycode())) return QCUnifyReturnValue.Warn("分类编码不存在或已删除");
        
        //判断新增字典项是否存在，存在则提示
        if (dictItemIsExist(dto.getId())) return QCUnifyReturnValue.Warn("新增字典项已经存在");
        
        //判断字典值：同一分分类下字典值不能重复，不同分类可以重复
        if (dictKeyisExist("",dto.getCategorycode(),dto.getK())) return QCUnifyReturnValue.Warn("新增分类下的字典值已经存在");
        
        //设置ID
        dto.setId(IdentifierUtil.randomUUID());
        
        //dto -> entity
        QcDictItem en = DictItemMapper.MAPPER.DictItemDtoToEntity(dto);
        
        if (itemRepository.insert(en) < 0x0) 
            return QCUnifyReturnValue.Warn("新增数据失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改字典项
     *
     * @param dto
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public String updateItem(DictItemDto dto){
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("修改字典项对象不能为空");
        if (StringUtils.isBlank(dto.getId())) return QCUnifyReturnValue.Warn("字典项编码不能为空");
        if (StringUtils.isBlank(dto.getCategorycode())) return QCUnifyReturnValue.Warn("字典分类编码不能为空");
        if (StringUtils.isBlank(dto.getK())) return QCUnifyReturnValue.Warn("字典值不能为空");
        if (StringUtils.isBlank(dto.getV())) return QCUnifyReturnValue.Warn("显示文本不能为空");

        //判断分类编码是否存在，不存在则提示
        if (!dictCategoryIsExist(dto.getCategorycode())) return QCUnifyReturnValue.Warn("分类编码不存在或已删除");

        //判断新增字典项是否存在，存在则提示
        if (!dictItemIsExist(dto.getId())) return QCUnifyReturnValue.Warn("修改字典项不存在");

        //判断字典值：同一分分类下字典值不能重复，不同分类可以重复
        if (dictKeyisExist(dto.getId(), dto.getCategorycode(),dto.getK())) return QCUnifyReturnValue.Warn("修改分类下的字典值已经存在");

        //dto -> entity
        QcDictItem en = DictItemMapper.MAPPER.DictItemDtoToEntity(dto);
        
        itemRepository.updateById(en);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除字典项
     *
     * @param itemId 字典项ID
     * @param isLogicDelete 是否为逻辑删除
     * @return 成功返回null，失败返回错误信息
     * @author Qucheng Tech
     * @since 2024/4/18
     */
    public String deleteItem(String itemId,boolean isLogicDelete){
        if (StringUtils.isBlank(itemId)) return QCUnifyReturnValue.Warn("字典项ID不能为空");
        
        if (isLogicDelete){
            //逻辑删除，修改记录状态标记，不删除记录
            LambdaUpdateWrapper<QcDictItem> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(QcDictItem::getFlag, ResourceStatusFlagEnum.DELETED)
                    .eq(QcDictItem::getItemid, itemId);
            itemRepository.update(null, wrapper);
        }else {
            itemRepository.deleteById(itemId);
        }
        
        return QCUnifyReturnValue.Success();
    }
    

    /***
     * 获取指定字典分类的状态为有效的集合
     *
     * @param categoryCode 字典分类
     * @return java.util.List<qc.common.core.pair.KeyValuePairDto>
     * @author QuCheng Tech
     * @since 2024/3/10
     */
    public List<KeyValuePairDto> getCategoryValidValues(String categoryCode) {
        return getCategoryValues(categoryCode, true);
    }

    /***
     * 获取指定字典分类的所有集合，不管状态
     *
     * @param categoryCode 字典分类
     * @return java.util.List<qc.common.core.pair.KeyValuePairDto>
     * @author QuCheng Tech
     * @since 2024/3/10
     */
    public List<KeyValuePairDto> getCategoryAllValues(String categoryCode) {
        return getCategoryValues(categoryCode, false);
    }

    /***
     * 获取指定字典分类的节后，可以指定状态
     *
     * @param categoryCode 字典分类
     * @param onlyValid 是否仅为有效状态，为true表示只查询状态为有效，为false表示不管状态
     * @return java.util.List<qc.common.core.pair.KeyValuePairDto>
     * @author QuCheng Tech
     * @since 2024/3/10
     */
    public List<KeyValuePairDto> getCategoryValues(String categoryCode, boolean onlyValid) {
        if (StringUtils.isNotBlank(categoryCode)) {
            LambdaQueryWrapper<QcDictItem> wrapper = new LambdaQueryWrapper<>();

            //查询字典项值时只要KV列
            wrapper.select(QcDictItem::getK, QcDictItem::getV);

            //根据分类进行筛选
            wrapper.eq(QcDictItem::getDictcode, categoryCode);
            //只要有效标记为true时只查询状态为正常的
            if (onlyValid)
                wrapper.eq(QcDictItem::getFlag, ResourceStatusFlagEnum.NORMAL);

            //排序，排序号
            wrapper.orderByAsc(QcDictItem::getOdr);
            //再按名称排序
            wrapper.orderByAsc(QcDictItem::getV);

            List<QcDictItem> ens = itemRepository.selectList(wrapper);
            if (ens != null && ens.size() > 0x0) {
                //转换为Map
                //return ens.stream().collect(Collectors.toMap(QcDictItem::getK, QcDictItem::getV));
                //转换为KV集合
                return DictItemMapper.MAPPER.entitysToKVPairList(ens);
            }
        }

        return null;
    }

    /**
     * 判断字典分类对象是否存在
     * 
     * @param dictCode 字典分类编码
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2024/4/18
     */
    private boolean dictCategoryIsExist(String dictCode){
        if (StringUtils.isNotBlank(dictCode)){
            QcDictCategory en = categoryRepository.selectById(dictCode);
            if (Objects.nonNull(en)) return true;
        }
        return false;
    }
    /**
     * 判断字典项对象是否存在
     *
     * @param itemId 字典项ID
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2024/4/18
     */
    private boolean dictItemIsExist(String itemId){
        if (StringUtils.isNotBlank(itemId)){
            QcDictItem en = itemRepository.selectById(itemId);
            if (Objects.nonNull(en)) return true;
        }
        return false;
    }

    /**
     * 判断字典项的字典值是否存在
     * 同一分类下不重复，不同分类下可以重复
     *
     * @param dictCode 字典编码
     * @param key 字典值
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2024/4/30
     */
    private boolean dictKeyisExist(String itemId,String dictCode,String key){
        if (StringUtils.isNotBlank(dictCode) && StringUtils.isNotBlank(key)){
            LambdaQueryWrapper<QcDictItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(QcDictItem::getDictcode,dictCode);
            wrapper.eq(QcDictItem::getK,key);
            wrapper.ne(QcDictItem::getItemid,itemId);
            QcDictItem en = itemRepository.selectOne(wrapper);
            if (Objects.nonNull(en)) return true;
        }
        return false;
    }
    
}
